class AccountController < ApplicationController
  # If you want "remember me" functionality, add this before_filter to Application Controller
  #before_filter :login_from_cookie

  # Los siguientes requieren un usuario logeado (cualquiera)
  before_filter :login_required, :only => [:index, :list, :edit, :view, :logout, :quit, :remove]

  # Los siguientes requieren un usuario logeado como administrador
  before_filter :admin_required, :only => [:signup_admin, :signup_instructor]

  # Esta es la página por default de todo el sistema.
  # Esto es lo que hace:
  #  Requiere login (redirije a account/login si no está logeado)
  #  Muestra los cursos inscritos, y los próximos eventos/asignaciones
  #  Muestra un enlace a courses/list
  #  Muestra un enlace a events/list
  #  Si es Instructor, muestra las últimas tareas que se han subido y que no han
  #     sido calificadas, de los cursos a los que está inscrito.
  #  Si es administrador muestra los últimos usuarios que han hecho login.
  def index
    @title = "Bienvenido."
    @courses = self.current_user.courses
    if self.current_user.is_instructor?
      @assignments = @courses.map { |c| c.assignments }.flatten.select {|a| a.has_ungraded_answers? }
    elsif self.current_user.is_student?
      # TBD: Esto se puede simplificar si se denormaliza las relaciones, y se
      # crea una relacion N:M entre events y users.
      @assignments = @courses.map { |c| c.assignments }.flatten - self.current_user.assignment_answers.map { |aa| aa.assignment }
    else
      @users = User.find(:all, :conditions => 'last_login IS NOT NULL' ,  :order => 'last_login DESC', :limit => 10)
    end

    if self.current_user.is_administrator?
      @events = Event.find(:all, :conditions => [ 'expire_date >= ?', Time.now ], :order => 'due_date ASC', :limit => 10)
      @configs = SystemSetting.find(:all)
    else
      @events = @courses.map { |c| c.events }.flatten
    end
  end

  # Esta es la accion de login. Si el usuario no esta logeado, esta es la
  # primera página que ve.
  # Esto es lo que hace:
  #  NO Requiere login.
  #  Permite al usuario introducir su username/password.
  #  Muestra un enlace a account/recover para que le recuerden su password.
  #  Muestra un enlace a account/signup para que añadir otro estudiante.
  #  Redirije a account/index si el usuario ya está logeado.
  def login
    if logged_in?
      redirect_to :action => 'index'
      return
    end
    @title = "Login"

    # Sólo procesar los datos si se envió un password y usuario.
    return unless request.post?

    # Intentar autenticar con las credenciales dadas.
    self.current_user = User.authenticate(params[:login], params[:password])

    if logged_in?
      # Si el usuario solicitó (con un checkbox) que su usuario sea logeado
      # automágicamente...
      if params[:remember_me] == "1"
        self.current_user.remember_me
        cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
      end

      flash[:notice] = "Bienvenido. Último acceso: #{self.current_user.last_last_login}"
      redirect_back_or_default(:controller => 'account', :action => 'index')
    else
      flash[:error] = "Nombre de usuario o contrase&ntilde;a incorrectos."
    end
  end

  # Esta es la accion de signup. Si el usuario no está logeado, puede añadir un
  # nuevo usuario (con rol de estudiante) aquí.
  # Esto es lo que hace:
  #  NO requiere login.
  #  Pregunta al usuario todos los datos del modelo User y el modelo Profile
  def signup
    if self.current_user != :false and not self.authorized?
      flash[:notice] = "¿Para que quieres otro usuario?"
      redirect_to :action => 'index'
      return
    end

    @title = 'Crear nuevo usuario'

    @user = User.new(params[:user])
    @profile = Profile.new(params[:profile])
    @user[:kind] = 'Student'
    @profile.user = @user

    return unless request.post?

    #@user.activation_code = rand(0xFFFFFFF7).to_s unless self.is_admin?
    User.transaction do
      @user.save!
      @profile.save!
    end
    if not self.is_admin?
#      UserNotifier.deliver_signup_notification(@user)
      flash[:notice] = "El usuario #{@user.login} ha sido creado. Revisa tu mail para activar la cuenta."
    else
      flash[:notice] = "El usuario #{@user.login} ha sido creado."
    end
    
    redirect_back_or_default(:controller => 'account', :action => 'login') if not self.is_admin?
    redirect_back_or_default(:controller => 'account', :action => 'index') if self.is_admin?

  rescue ActiveRecord::RecordInvalid
  end

  # Esta es la accion de signup_admin. Si el usuario es un administrador, puede
  # añadir un nuevo administrador. Es por lo demás, igual a signup
  def signup_admin
    @title = 'Creando nuevo administrador'
    @user = User.new(params[:user])
    @profile = Profile.new(params[:profile])
    @user[:kind] = 'Admin'
    @profile.user = @user
    unless request.post?
      render :action => 'signup'
      return
    end
    User.transaction do
      @user.save!
      @profile.save!
    end
    flash[:notice] = "El usuario #{@user.login} ha sido creado."
    redirect_back_or_default :controller => 'account', :action => 'index'
  rescue ActiveRecord::RecordInvalid
    render :action => 'signup'
  end

  # Esta es la accion de signup_instructor. Si el usuario es un administrador, puede
  # añadir un nuevo instructor. Es por lo demás, igual a signup
  def signup_instructor
    @title = 'Creando nuevo instructor'
    @user = User.new(params[:user])
    @profile = Profile.new(params[:profile])
    @user[:kind] = 'Instructor'
    @profile.user = @user
    unless request.post?
      render :action => 'signup'
      return
    end
    User.transaction do
      @user.save!
      @profile.save!
    end
    flash[:notice] = "El usuario #{@user.login} ha sido creado."
    redirect_back_or_default :controller => 'account', :action => 'index'
  rescue ActiveRecord::RecordInvalid
    render :action => 'signup'
  end
  
  # Esta es la accion de logout. Si el usuario esta logeado, elimina su sesión
  # haciendo que efectivamente no esté logeado.
  # Esto es lo que hace:
  #  SI requiere que el usuario este logeado
  #  Redirije a account/index (a menos que alguna página solicite ser
  #  recordada).
  def logout
    self.current_user.forget_me if logged_in?

    cookies.delete :auth_token
    reset_session

    flash[:notice] = "Haz salido del sistema."
    redirect_to(:controller => 'account', :action => 'login')
  end

  # Esta es la accion del list. Muestra una lista de usuarios si el usuario está
  # logeado.
  # Esto es lo que hace:
  #  Requiere que el usuario esté logeado
  #  Lista todos los usuarios.
  #  Para el usuario actual permite modificar el profile
  #  Para todos los usuarios permite ver su profile
  def list
    @title = "Todos los usuarios."
    @users = User.find(:all, :include => :profile)
  end



  # Esta aparece cuando la acción genera un access_denied, pero el usuario ya
  # está logeado. Basicamente le dice que no tiene acceso...
  def denied_page
    @title = "ACCESO DENEGADO"
    @user = self.current_user
  end
  
  # Esta es la accion de edit. Si el usuario está logeado, edita su profile. Si
  # el usuario es un administrador, puede editar cualquier profile.
  def edit
    @title = "Editando perfil."
    @id = params[:id]

    if @id.nil? or @id.to_i == self.current_user.id
      @user = self.current_user
      @profile  = @user.profile
    elsif self.is_admin?
        @user = User.find(@id, :include => :profile)
        @profile = @user.profile
    else
        access_denied
        return
    end
    return unless request.post?
    User.transaction do
      @user.update_attributes! params[:user]
      @profile.update_attributes! params[:profile]
    end
    session[:stylesheet] = @user.stylesheet if @id.to_i == self.current_user.id or @id.nil?
    redirect_to :action => 'view'
  rescue ActiveRecord::RecordInvalid
  end

  # Esta es la accion de view. Si el usuario está logeado, muestra el perfil de
  # un usuario dado, o su propio perfil.
  def view
    @title = "Ver Perfil"
    @id = params[:id]
    if @id.nil?
      @userdata = self.current_user
      @profile = @userdata.profile
    else
      @userdata = User.find(@id, :include => :profile)
      @profile = @userdata.profile
    end
  end

  # Ésta es la acción de recover_password. Permite cambiar el password a un
  # usuario.
  # Esto es lo que hace:
  #  Pregunta un password
  #  Envía un correo con una liga para generar un password nuevo.
  #  Al recibir la liga, genera un nuevo password, y lo imprime.
  def recover_password
    @title = "Recuperar password."
    id = params[:id]
    if id.nil?
      if request.post?
        user = User.find_by_login(params[:login])
        if not user.nil?
          # Enviar mail
#          UserNotifier.deliver(UserNotifier.create_recover(user))
          flash[:notice] = "El usuario ha sido notificado."
        else
          flash[:error] = "No conozco al usuario &quot;#{params[:login]}&quot;"
        end
        redirect_to :action => 'index'
      end
    else
      user = User.find_by_crypted_password(id)
      if user.nil?
        flash[:error] = "El usuario no fue encontrado."
      else
        user.password = "%08X" % rand
        user.password_confirmation = user.password
        user.save!
        flash[:notice] = "Tu nuevo password es: #{user.password}"
        redirect_to :action => 'login'
      end
    end
  rescue ActiveRecord::RecordInvalid
    flash[:error] = "Error generando un password nuevo."
  end

  # Activa un usuario.
  # TODO: El problema está con enviar el mail, así que de mientras no
  # necesitamos activación.
  def activate
    if params[:id].nil?
      flash[:error] = "No hay codigo por activar!"
      redirect_to :action => 'index'
      return
    end
    user = User.find_by_activation_code(params[:id])
    if user.nil?
      flash[:error] = "No pude encontrar el codigo de activación #{params[:id]}"
    else
      flash[:notice] = "Gracias por entrar a #{StringSetting.find_by_name("site-name").value} (Powered by Contenid-OS)"
      user.activation_code = nil
    end
    redirect_to :action => 'index'
    self.current_user= user
  end

  def remove
    #  * Sólo acepta por POST (si no, hacer un redirect_back).
    #  * Tienes que ser ese usuario, o ser un administrador.
    #  1. Hacer logout del usuario actual a menos que sea administrador.
    #  2. Eliminar entrada de User (debería llevarse las entradas en Profile,
    #  AssignmentAnswer, AnswerBlob, y las relaciones con Course).
    #  3. Redirigir a '/'
    redirect_back_or_default(:controller => 'account', :action => 'index') if not request.post?
    if params[:id].nil? or params[:id].to_i == self.current_user.id
      user = self.current_user
      # Hacer logout
      self.current_user.forget_me

      cookies.delete :auth_token
      reset_session

      user.destroy
    elsif self.is_admin?
      user = User.find(params[:id])
      user.destroy
    end
    flash[:notice] = "Usuario eliminado."
    redirect_to :controller => 'account', :action => 'index'
  rescue ActiveRecord::RecordNotFound
    flash[:error] = "Usuario no encontrado #{params[:id]}"
    redirect_to :controller => 'account', :action => 'index'
  end
end
